package com.java.st.lib.tools.net;

import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;

import org.apache.http.client.config.RequestConfig;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.config.SocketConfig;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.ssl.TrustStrategy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.java.st.lib.tools.base.ExceptionUtil;

public class PoolingHttpInstance {
	private static final Logger logger = LoggerFactory.getLogger(PoolingHttpInstance.class);

	private static class InstanceHolder {
		public static final PoolingHttpInstance instance = new PoolingHttpInstance();
	}

	public static PoolingHttpInstance getInstance() {
		return InstanceHolder.instance;
	}

	private static PoolingHttpClientConnectionManager poolingConnMgr;

	private PoolingHttpInstance() {
		poolingConnMgr = createConnectionManager();
	}

	public HttpClientBuilder getHttpClientBuilder() {
		poolingConnMgr.setDefaultMaxPerRoute(20);
		poolingConnMgr.setMaxTotal(200);
		SocketConfig socketConfig = SocketConfig.custom().setSoTimeout(10000).setTcpNoDelay(true).build();
		RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(10000).setConnectTimeout(10000)
				.setConnectionRequestTimeout(10000).build();
		poolingConnMgr.setDefaultSocketConfig(socketConfig);
		poolingConnMgr.setValidateAfterInactivity(500);
		HttpClientBuilder builder = HttpClients.custom().setDefaultSocketConfig(socketConfig)
				.setDefaultRequestConfig(requestConfig).setConnectionManager(poolingConnMgr);
		return builder;
	}

	@SuppressWarnings("unchecked")
	private PoolingHttpClientConnectionManager createConnectionManager() {
		SSLContext sslContext = null;
		try {
			sslContext = SSLContexts.custom().loadTrustMaterial(new TrustStrategy() {
				@Override
				public boolean isTrusted(java.security.cert.X509Certificate[] chain, String authType)
						throws CertificateException {
					return true;
				}

			}).build();
		} catch (KeyManagementException e) {
			logger.error(ExceptionUtil.stackTraceText(e));
		} catch (NoSuchAlgorithmException e) {
			logger.error(ExceptionUtil.stackTraceText(e));
		} catch (KeyStoreException e) {
			logger.error(ExceptionUtil.stackTraceText(e));
		}

		if (sslContext == null) {
			return new PoolingHttpClientConnectionManager();
		}

		HostnameVerifier hostnameVerifier = new HostnameVerifier() {
			@Override
			public boolean verify(String hostname, SSLSession session) {
				return true;
			}
		};
		SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, new String[] { "TLSv1" }, null,
				hostnameVerifier);

		@SuppressWarnings("rawtypes")
		Registry registry = RegistryBuilder.create().register("http", PlainConnectionSocketFactory.INSTANCE)
				.register("https", sslsf).build();
		return new PoolingHttpClientConnectionManager(registry);
	}
}
